﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
using TTEngine.Graphics;
using TTEngine.Impl.Avalonia;
using TTEngine.Resource;
using TTEngine.TTMath;
//using static voidbox.Code.JsEngine;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using Microsoft.CodeAnalysis.MSBuild;
using TTEngine;

namespace voidbox.Code
{
    public class VBApp : IDisposable
    {
        public readonly VBAppConfig Config;
        //public ScriptObject callupdate;

        //public ScriptObject callrender;

        System.IO.Compression.ZipArchive zip;
        public CommonResource gfx_resource;
        public TTEngine.Graphics.Batcher gfx_batcher;
        private AssemblyLoadContext dllLoadContext;
        private List<Assembly> loadedAssemblies = new List<Assembly>();

        public IUserApp userapp;
        public VBApp(string path)
        {
            this.Path = path;
            if (System.IO.File.Exists(path))
            {
                IsPack = true;
                zip = System.IO.Compression.ZipFile.OpenRead(path);
            }
            else if (System.IO.Directory.Exists(path))
            {
                IsPack = false;
            }
            else
            {
                //AppError 是 特殊的
                throw new Exception("给定的路径既不是Pack 也不是目录，无法加载App");
            }
            this.Config = new VBAppConfig();
            this.Config.Init(this.LoadText("app.ini"));

            Debuger.Enable = this.Config.Debug;
            this.gfx_resource = new CommonResource();
            this.gfx_resource.Init(TTEngine.Resource.ResourcePackage.Create());
            this.gfx_batcher = new TTEngine.Graphics.Batcher(this.gfx_resource);
        }
        public bool IsPack
        {
            get;
            private set;
        }
        public string Path
        {
            get;
            private set;
        }
        public void CallUpdate(float delta)
        {
            userapp?.OnUpdate(delta);
        }
        public void CallRender()
        {

            try
            {
                userapp?.OnRender();
            }
            catch (Exception err)
            {
                Debug.WriteLine(err.Message);
            }

            Runtime.activeTarget.RenderInfo.DrawStats(gfx_resource, gfx_batcher.GetPackedTextureBatcher(), new voidbox.fAABB(0, 0, 200, 64), 1, true);

        }
        public void Dispose()
        {
            if (zip != null)
            {
                zip.Dispose();
            }

            TTEngine.Resource.ResourcePackage.DestoryPackage(gfx_resource.Package, true);
            gfx_resource = null;

            UnloadDLL();
        }
        void UnloadDLL()
        {
            // 卸载 DLL
            if (dllLoadContext != null)
            {
                userapp = null;
                dllLoadContext.Unload();

                dllLoadContext = null;

                loadedAssemblies.Clear();
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
        }
        public void ReloadCode()
        {
            UnloadDLL();
            Resume();
        }
        public byte[] LoadBinary(string filename)
        {
            if (!IsPack)
            {
                var path = System.IO.Path.Combine(Path, filename);
                if (System.IO.File.Exists(path))
                {
                    return System.IO.File.ReadAllBytes(path);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                var entry = zip.GetEntry(filename);
                if (entry == null) return null;
                var bytes = new byte[entry.Length];
                using var ms = entry.Open();
                ms.Read(bytes, 0, bytes.Length);
                return bytes;
            }
        }
        public string LoadText(string filename)
        {
            if (!IsPack)
            {
                return System.IO.File.ReadAllText(System.IO.Path.Combine(Path, filename));
            }
            else
            {
                var bts = LoadBinary(filename);
                return System.Text.Encoding.UTF8.GetString(bts);
            }
        }

        public string[] FindFiles(params string[] filters)
        {
            if (filters == null || filters.Length == 0 || filters.All(f => string.IsNullOrWhiteSpace(f)))
            {
                // 返回所有文件
                if (!IsPack)
                {
                    return System.IO.Directory.GetFiles(Path, "*", System.IO.SearchOption.AllDirectories);
                }
                else
                {
                    return zip.Entries.Select(e => e.FullName).ToArray();
                }
            }
            else
            {
                var result = new HashSet<string>();
                if (!IsPack)
                {
                    foreach (var filter in filters)
                    {
                        if (!string.IsNullOrWhiteSpace(filter))
                        {
                            foreach (var file in System.IO.Directory.GetFiles(Path, filter, System.IO.SearchOption.AllDirectories))
                                result.Add(file);
                        }
                    }
                }
                else
                {
                    foreach (var filter in filters)
                    {
                        if (!string.IsNullOrWhiteSpace(filter))
                        {
                            var pattern = "^" + System.Text.RegularExpressions.Regex.Escape(filter).Replace("\\*", ".*").Replace("\\?", ".") + "$";
                            var regex = new System.Text.RegularExpressions.Regex(pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                            foreach (var entry in zip.Entries.Where(e => regex.IsMatch(e.FullName)))
                                result.Add(entry.FullName);
                        }
                    }
                }
                return result.ToArray();
            }
        }

        //读取配置文件，初始化绘制
        public void Init()
        {
            Resume();
        }
        //恢复和初始化差不多，先分俩函数吧，仅在加载了多个app 关闭了后面的才会发生
        public void Resume()
        {
            Root.SetOutputSize(Config.PixelWidth, Config.PixelHeight);

            var win = (TTEngine.API.view as GLMainView).GetWindow();
            if (win != null)
                win.Title = "VoidBox " + this.Config.Title;

            var ext = System.IO.Path.GetExtension(Config.Load[0]).ToLower();
            if (ext == ".csproj")
            {
                var task = LoadCsProj(Config.Load[0]);

            }
            else if (ext == ".dll")
            {
                // 先用 LoadBinary 加载 DLL 文件为字节数组
                List<AssBytes> list = new List<AssBytes>();
                foreach (var file in Config.Load)
                {
                    var pdbfile = file.Replace(".dll", ".pdb");
                    AssBytes assb = new AssBytes();
                    assb.dll = LoadBinary(file);
                    assb.pdb = LoadBinary(pdbfile);
                    list.Add(assb); ;
                }

                LoadDlls(list.ToArray());
            }
        }
        void StartApp()
        {
            var userAppTypes = new List<Type>();
            foreach (var asm in loadedAssemblies)
            {
                var types = asm.GetExportedTypes().Where(t => typeof(voidbox.IUserApp).IsAssignableFrom(t) && !t.IsAbstract && t.IsClass).ToList();
                userAppTypes.AddRange(types);
            }
            if (userAppTypes.Count == 0)
            {
                throw new Exception("未找到继承自 IUserApp 的类型");
                return;
            }
            if (userAppTypes.Count > 1)
            {
                throw new Exception($"找到多个继承自 IUserApp 的类型: {string.Join(", ", userAppTypes.Select(t => t.FullName))}");
            }
            var type = userAppTypes[0];
            userapp = Activator.CreateInstance(type) as IUserApp;
            Debug.WriteLine($"已创建 IUserApp 实例: {type.FullName}");
            // 可在此处保存 instance 或做后续处理

            userapp.OnStart(Root.AppInterface);
        }
        async Task LoadCsProj(string csprojPath)
        {
            if (IsPack)
            {
                Root.AppInterface.Debug.Log("APPError","zip模式下不支持编译csproj");
                throw new Exception("zip模式下不支持编译csproj");
            }

            string csprojFullPath = System.IO.Path.IsPathRooted(csprojPath) ? csprojPath : System.IO.Path.Combine(System.IO.Path.GetFullPath(Path), csprojPath);
            string csprojDir = System.IO.Path.GetDirectoryName(csprojFullPath);
            string dllName = System.IO.Path.GetFileNameWithoutExtension(csprojFullPath) + ".dll";
            string pdbName = System.IO.Path.GetFileNameWithoutExtension(csprojFullPath) + ".pdb";
            string dllPath = System.IO.Path.Combine(csprojDir, dllName);
            string pdbPath = System.IO.Path.Combine(csprojDir, pdbName);

            var workspace = MSBuildWorkspace.Create(new Dictionary<string, string> { { "Configuration", "Debug" } });
            var project = await workspace.OpenProjectAsync(csprojFullPath);
            var compilation = await project.GetCompilationAsync();
            using var dllFile = System.IO.File.Open(dllPath, System.IO.FileMode.Create);
            using var pdbFile = System.IO.File.Open(pdbPath, System.IO.FileMode.Create);
            var emitResult = compilation.Emit(dllFile, pdbFile);
            dllFile.Close();
            pdbFile.Close();
            if (!emitResult.Success)
            {
                var errors = string.Join("\n", emitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Select(d => d.ToString()));
                Root.AppInterface.Debug.Log("APPError", "Roslyn 编译失败: " + errors);
                throw new Exception("Roslyn 编译失败: " + errors);
            }
            LoadDlls([new AssBytes { dll= System.IO.File.ReadAllBytes(dllPath),
                pdb=System.IO.File.ReadAllBytes(pdbPath) }]);

        }
        public class AssBytes
        {
            public byte[] dll;
            public byte[] pdb;
        }
        void LoadDlls(AssBytes[] dllBytesArray)
        {
            // 如果已存在上下文，先卸载
            UnloadDLL();
            dllLoadContext = new AssemblyLoadContext($"VBApp_DLLContext_{Guid.NewGuid()}", isCollectible: true);
            foreach (var dllBytes in dllBytesArray)
            {
                try
                {
                    using var ms = new System.IO.MemoryStream(dllBytes.dll);

                    using var mspdb = (dllBytes.pdb != null) ? new System.IO.MemoryStream(dllBytes.pdb) : null;
                    var asm = dllLoadContext.LoadFromStream(ms, mspdb);
                    loadedAssemblies.Add(asm);
                    Debug.WriteLine($"Loaded DLL from memory, length: {dllBytes.dll.Length}");
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"Failed to load DLL from memory, Error: {ex.Message}");
                }
            }
            StartApp();
        }

    }
}
